public class PlotSynchronizedVsNumSynapses {
    static final int NUM_NEURONS = 40 ;
    static final int NUM_BIASED = 10 ;
    
    // how many runs to do for each data point
    static final int AVG_OVER_RUNS = 6 ;
    
    static final int SMOOTH_OVER = 50 ;
    
    static final int numSynapses = NUM_NEURONS * ( NUM_NEURONS - 1 ) ;
    
    private static void calculateSynchronizedInRange( int start , int stop , INeuralNetExperiment e , double [ ] x , double [ ] y ) {
        ExperimentAnalyzer a ;
        int i , j ;
        double total ;
        
        for ( i = start ; i < stop ; i ++ ) {
            e.setParam( "initial syn %" , "" + 100 * ( ( double ) i ) / numSynapses ) ;
            total = 0 ;
            for ( j = 0 ; j < AVG_OVER_RUNS ; j ++ ) {
                e.run( ) ;
                a = new ExperimentAnalyzer( e ) ;
                total += a.numSynchronized( ) ;
            }
            x [ i ] = i ;
            y [ i ] = total / AVG_OVER_RUNS ;
            System.out.println( "With " + i + " initial, " + y [ i ] + " synchronized." ) ;
        }
    }
    
    public static void main( String [ ] args ) {
        final INeuralNetExperiment e = new Experiment2( ) , e2 ;
        final INeuron neuron = new MapNeuron( ) ;
//		final ISynapse synapse = new STDPSynapse ( null , null , 0. ) ;
        final ISynapse synapse = new PureHebbianPlasticity( null , null , 0. ) ;
        Thread t1 , t2 ;
        Graph g ;
        int i , j ;
        double total ;
        
        // sinusoidal current with amp=.5, period = 50 until time=6000
        IAppliedCurrent iApp = new SinusoidalCurrent( .5 , 50 , 0 , 0 , 6000 ) ;
        
        final double [ ] x = new double [ numSynapses ] ;
        final double [ ] y = new double [ numSynapses ] ;
        
        // setup the experiment
        e.setCurrent( iApp ) ;
        e.setParam( "numNeurons" , "" + NUM_NEURONS ) ;
        e.setParam( "numBiased" , "" + NUM_BIASED ) ;
        e.setParam( "runTime" , "10000" ) ;
        e.setParam( "gridSize" , "40" ) ;
        e.setParam( "k" , "1" ) ;
        e.setParam( "synapse variance" , ".005" ) ;
        e2 = e.clone( ) ;
        e.init( neuron , synapse ) ;
        e2.init( neuron , synapse ) ;
        t1 = new Thread( new Runnable( ) {
            public void run( ) {
                calculateSynchronizedInRange( 0 , 2 * numSynapses / 3 , e , x , y ) ;
            }
        } ) ;
        t2 = new Thread( new Runnable( ) {
            public void run( ) {
                calculateSynchronizedInRange( 2 * numSynapses / 3 , numSynapses , e2 , x , y ) ;
            }
        } ) ;
        t1.start( ) ;
        t2.start( ) ;
        try {
            t1.join( ) ;
            t2.join( ) ;
        } catch ( Exception ex ) {
            System.out.println( "Thread aborted unusually." ) ;
            System.exit( 0 ) ;
        }
        
        g = new Graph( ) ;
        g.addCurve( x , y , null , true ) ;
        g.autoWindow( ) ;
        g.autoLabel( ) ;
        g.makeWindow( 640 , 480 , Graph.QUIT_ON_CLOSE , "Num Synchronized Neurons vs Num Synapses Unsmoothed" ) ;
        
        // smooth the curve by averaging forward by smooth_over
        for ( i = 0 ; i < numSynapses ; i ++ ) {
            total = 0 ;
            for ( j = i ; j < Math.min( i + SMOOTH_OVER , numSynapses ) ; j ++ ) {
                total += y [ j ] ;
            }
            total /= Math.min( i + SMOOTH_OVER , numSynapses ) - i ;
            y [ i ] = total ;
        }
        g = new Graph( ) ;
        g.addCurve( x , y , null , true ) ;
        g.autoWindow( ) ;
        g.autoLabel( ) ;
        g.makeWindow( 640 , 480 , Graph.QUIT_ON_CLOSE , "Num Synchronized Neurons vs Num Synapses Smoothed" ) ;
    }
}
